/**************************************************************************************
*
*	Copyright (C) 2009 - 2012 Brent Andrew O. Chua - See LICENSE.txt for more info.
*		
*	Filename	-	ComponentCamera.h
*
*	Description -	ComponentCamera object.
*
*	Comments	-	This is a camera-centric renderer. All render entry list are generated
*					by this camera component.
*
*	Modification History:
*			Name			   Date					Description
*			MrCodeSushi	-	07/23/2012	-	Creation of this file
**************************************************************************************/
#ifndef _PSX_COMPONENT_CAMERA_H_
#define _PSX_COMPONENT_CAMERA_H_

#include "PulseSTD.h"
#include "IComponent.h"
#include "Matrix4x4.h"
#include "RenderView.h"
#include "RenderEntryProjection.h"
#include "RenderEntryView.h"
//#include "RenderPathLightPrePass.h"
#include "RenderPathForwardPlus.h"
//#include "RenderEntryBindParameters.h"

namespace Pulse
{
	PSX_EnumBegin( EProjection )
		UNKNOWN = -1,
		Perspective,
		Orthogonal,
	PSX_EnumEnd()

	class ComponentCamera : public IComponent
	{
	public:

		ComponentCamera( Actor *pOwner );

		virtual ~ComponentCamera( void );

		virtual EErrorCode::Type Initialize( XMLElementPtr pElem );

		virtual const EComponent::Type GetType( void ) const { return EComponent::CAMERA; }

		virtual const CHAR * GetName( void ) const { return PSX_String("Camera"); }

		virtual void Update( FLOAT dt );

		void SetActive( BOOL bActive );

		const BOOL IsActive( void ) const { return m_bActiveCamera; }

		void SetProjectionPerspective( FLOAT _near, FLOAT _far, FLOAT aspect, FLOAT fov );

		void SetProjectionOrthogonal( UINT width, UINT height, FLOAT _near, FLOAT _far );

		Matrix4x4 * GetProjectionMatrix( void ) { return &m_proj; }

		const EProjection::Type GetProjectionType( void ) const { return m_projType; }
		
		void SetLocalizedRendering( const BOOL bEnable )  { m_bLocalizedRendering = bEnable; }

		const BOOL IsLocalizedRendering( void ) const { return m_bLocalizedRendering; }

		CameraRenderPathSettingsFP * GetRenderPathSettings( void ) { return m_pRenderPathSettings; }

		const FLOAT GetNearClipPlane( void ) const	{ return m_near;	}
		const FLOAT GetFarClipPlane( void ) const	{ return m_far;		}
		const FLOAT GetAspectRatio( void ) const	{ return m_aspect;	}
		const FLOAT GetFiledOfView( void ) const	{ return m_fov;		}

		RenderView * GetRenderView( void ) { return &m_renderView; }

		void Render( Scene *pScene );

	private:

		void BuildProjectionParameters( void ) const;

	private:

		// WindowView event delegates
		//////////////////////////////

		void OnWindowViewResize( IEvent *pEvent );

		void OnWindowViewDestroy( IEvent *pEvent );

		// Actor Event Delegates 
		/////////////////////////

		void OnRender( IEvent *pEvent );

		void OnTransform( IEvent *pEvent );

	private:

		BOOL m_bActiveCamera;
		BOOL m_bLocalizedRendering;

		EProjection::Type m_projType;

		UINT m_width;
		UINT m_height;
		
		FLOAT m_near;
		FLOAT m_far;
		FLOAT m_aspect;
		FLOAT m_fov;

		Matrix4x4 m_proj;
		Matrix4x4 *m_pWorldTransform;
		Matrix4x4 m_view;
		Matrix4x4 m_viewProj;
		Matrix4x4 m_invViewProj;

		// WindowView dependency
		BOOL	m_bWindowViewExist;	// HACK: This looks ugly...

		// Render parameter bindings
		ParameterBinderMatrixRef	*m_pParamProj;
		ParameterBinderMatrixRef	*m_pParamView;
		ParameterBinderMatrixRef	*m_pParamViewProj;
		ParameterBinderMatrixRef	*m_pParamInvViewProj;
		ParameterBinderVector3		*m_pParamPosWS;
		ParameterBinderScalar		*m_pParamClipNear;
		ParameterBinderScalar		*m_pParamClipFar;

		// Rendering
		Renderer					*m_pRenderer;
		RenderView					m_renderView;
		RenderEntryViewport			*m_pREViewport;
		RenderEntryBindParameters	*m_pREBindParams;

		// HACK: We ultimately want a flexible render pass with
		//	various rendering applications.
		RenderPathForwardPlus		*m_renderPath;
		CameraRenderPathSettingsFP *m_pRenderPathSettings;
	};
}

#endif /* _PSX_COMPONENT_CAMERA_H_ */